package com.lvmama.pangolin.busi.timer;



import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.TriggerBuilder;
import org.quartz.impl.SchedulerRepository;

import com.lvmama.pangolin.busi.config.ConfigManager;
import com.lvmama.pangolin.common.ClassLoaderCache;
import com.lvmama.pangolin.common.StringTools;
import com.lvmama.pangolin.entity.Config;
import com.lvmama.pangolin.entity.Timer;



/**
 * 
* @ClassName: TimerManagerAssist 
* @Description: TODO定时任务辅助处理类
* @author yuanchi
* @date 2017年2月14日 下午3:16:28
 */
public class TimerManagerAssist 
{
	Logger logger = Logger.getLogger(TimerManagerAssist.class);
	private  List<Timer> jobList = new ArrayList<Timer>();
	
	public List<Timer> getAllJobList(){
		if(jobList==null)
			jobList = new ArrayList<Timer>();
		jobList.clear();
		List<Timer> timerList = new ArrayList<Timer>();
		if (timerList != null){	
			String timerCode = null;
			for (Timer timer : timerList){
				timerCode = timer.getTimer_code()+"_" + timer.getTask_id();
				CronTrigger crontrg=TimerManager.getInstance().getCronTrigger(timerCode);
				if(crontrg!=null){
					timer.setTimer_preFireTime(getPreFireTime(timerCode));
					timer.setTimer_nextFireTime(getNextFireTime(timerCode));
					timer.setTimer_valid(1);
				}else{
					timer.setTimer_preFireTime("");
					timer.setTimer_nextFireTime("");
					timer.setTimer_valid(0);
				}
				
				jobList.add(timer);
			}
		}
		return jobList;	
	}
	
	/**
	 * 动态加载定时任务
	 * @param timerCode
	 * @return
	 * @throws Exception
	 */
	public void loadValidJob(Timer timer) throws Exception{
		TimerManager timerManager = TimerManager.getInstance();
		if(timerManager.getScheduler()==null)
			timerManager.putScheduler(SchedulerRepository.getInstance().lookup("DefaultQuartzScheduler"));
		if(timerManager.getScheduler()==null)
			throw new Exception("定时任务未初始化！");
		String timeCode = timer.getTimer_code()+"_"+timer.getTask_id();
		String timer_className=timer.getTimer_classname();
		String timer_classsParam=timer.getTimer_param();
		String timer_cron=timer.getTimer_cron();
		Class jobClass=ClassLoaderCache.getClassByName(timer_className);
	    					
		JobDetail job = JobBuilder.newJob(jobClass).withIdentity("TIMER_"+timeCode)
				.usingJobData(TimerManager.TIMER_ID,timer.getTimer_id())
				.usingJobData(TimerManager.JOB_DATAKEY,timer_classsParam)
				.usingJobData(TimerManager.JOB_CODE, timer.getJob_code())
				.usingJobData(TimerManager.TIMER_CODE, timeCode)
				.usingJobData(TimerManager.TASK_ID, timer.getTask_id())
				.build();
	    CronTrigger trigger = (CronTrigger)TriggerBuilder.newTrigger().withIdentity("TRG_"+timeCode).withSchedule(CronScheduleBuilder.cronSchedule(timer_cron)).build();
	    timerManager.getScheduler().scheduleJob(job,trigger);	    
	    timerManager.putCronTrigger(timeCode, trigger);
	    timerManager.putTimer(timeCode, timer);
	    
	}
	
	/**
	 * 动态加载定时任务
	 * @param timerCode
	 * @return
	 * @throws Exception
	 */
	public void refreshJob(Timer timer) throws Exception{
		TimerManager timerManager = TimerManager.getInstance();
		String timeCode = timer.getTimer_code()+"_"+timer.getTask_id();
		Timer oldTimer = timerManager.getTimer(timeCode);
		if(oldTimer != null )
		{
			if("0".equals(timer.getTimer_status()) && 1 == timer.getTimer_valid())
			{
				removeJob(timeCode);
				loadValidJob(timer);
			}
			else
			{
				removeJob(timeCode);
			}
			
		}
		else
		{
			if("0".equals(timer.getTimer_status()) && 1 == timer.getTimer_valid())
			{
				loadValidJob(timer);
			}
		}
		
	    
	}
	
	/**
	 * 生效定时任务
	 * @param timerCode
	 * @return
	 * @throws Exception
	 */
	public boolean validJob(String timeCode) throws Exception{
		boolean isValid=false;
		TimerManager timerManager = TimerManager.getInstance();
		if(timerManager.getScheduler()==null)
			timerManager.putScheduler(SchedulerRepository.getInstance().lookup("DefaultQuartzScheduler"));
		if(timerManager.getScheduler()==null)
			throw new Exception("定时任务未初始化！");
		
		Timer timer = new Timer();
		String timer_className=timer.getTimer_classname();
		String timer_classsParam=timer.getTimer_param();
		String timer_cron=timer.getTimer_cron();
		Class jobClass=ClassLoaderCache.getClassByName(timer_className);
		JobDetail job = JobBuilder.newJob(jobClass).withIdentity("TIMER_"+timeCode)
				.usingJobData(TimerManager.TIMER_ID,timer.getTimer_id())
				.usingJobData(TimerManager.JOB_DATAKEY,timer_classsParam)
				.usingJobData(TimerManager.JOB_CODE, timer.getJob_code())
				.usingJobData(TimerManager.TIMER_CODE, timeCode)
				.usingJobData(TimerManager.TASK_ID, timer.getTask_id())
				.build();
	    CronTrigger trigger = (CronTrigger)TriggerBuilder.newTrigger().withIdentity("TRG_"+timeCode).withSchedule(CronScheduleBuilder.cronSchedule(timer_cron)).build();
	    timerManager.getScheduler().scheduleJob(job,trigger);	    
	    timerManager.putCronTrigger(timeCode, trigger);
	    timer.setTimer_valid(1);
	    timerManager.putTimer(timeCode, timer);
	    
	   //更新表中数据 update（timer）
	    int rownum = 0;
	    if(rownum>0)
	    	isValid=true;
	    		
		return isValid;
	}
	
	
	/**
	 * 失效定时任务
	 * @param timerCode
	 * @return
	 * @throws Exception
	 */
	public boolean unValidJob(String timerCode) throws Exception{
		boolean isUnValid=false;
		TimerManager timerManager = TimerManager.getInstance();
		if(timerManager.getScheduler()==null)
			timerManager.putScheduler(SchedulerRepository.getInstance().lookup("DefaultQuartzScheduler"));
		if(timerManager.getScheduler()==null || timerManager.getCronTrigger(timerCode)==null)
			throw new Exception("定时任务未初始化！");
		CronTrigger trigger = timerManager.getCronTrigger(timerCode);
		timerManager.getScheduler().deleteJob(trigger.getJobKey());
		timerManager.removeTrigger(timerCode);
		Timer timer = timerManager.getTimer(timerCode);
		timer.setTimer_valid(0);
		timerManager.removeTimer(timerCode);
		
		//更新表中数据 update（timer）
	    int rownum = 0;
		if(rownum>0)
	    	isUnValid=true;
		
		return isUnValid;
	}
	
	/**
	 * 移除任务
	 * @param timerCode
	 * @return
	 * @throws Exception
	 */
	public void removeJob(String timerCode) throws Exception
	{
		TimerManager timerManager = TimerManager.getInstance();
		if(timerManager.getScheduler()==null)
			timerManager.putScheduler(SchedulerRepository.getInstance().lookup("DefaultQuartzScheduler"));
		if(timerManager.getScheduler()==null || timerManager.getCronTrigger(timerCode)==null)
			throw new Exception("定时任务未初始化！");
		CronTrigger trigger = timerManager.getCronTrigger(timerCode);
		timerManager.getScheduler().deleteJob(trigger.getJobKey());
		timerManager.removeTrigger(timerCode);
		timerManager.removeTimer(timerCode);
		
	}
	
	/**
	 * 立即执行定时任务
	 * @param timerCode
	 * @throws Exception
	 */
	public boolean fireJob(String timerCode) throws Exception{
		boolean result = false;
		try {
			if(TimerManager.getInstance().getScheduler()==null || TimerManager.getInstance().getCronTrigger(timerCode)==null)
				throw new Exception("定时任务未初始化！");
			CronTrigger trigger = TimerManager.getInstance().getCronTrigger(timerCode);
			TimerManager.getInstance().getScheduler().triggerJob(trigger.getJobKey());
			result = true;
			logger.info("[TimerManagerAssist]执行定时任务成功！");
		} catch (Exception e) {
			result = false;
			logger.info("[TimerManagerAssist]执行定时任务失败！",e);
		}
		return result;
	}
	
	/**
	 * 获取任务上次执行时间
	 * @param timerCode
	 * @return
	 */
	public String getPreFireTime(String timerCode){
		CronTrigger crontrg=TimerManager.getInstance().getCronTrigger(timerCode);
		Date date=null;
		if(crontrg!=null && (date=crontrg.getPreviousFireTime())!=null){
			return StringTools.date2String(date, "yyyy-MM-dd HH:mm:ss");
		}else{
			return "";
		}		
	}
	
	/**
	 * 获取任务下次执行时间
	 * @param timerCode
	 * @return
	 */
	public String getNextFireTime(String timerCode){
		CronTrigger crontrg=TimerManager.getInstance().getCronTrigger(timerCode);
		Date date=null;
		if(crontrg!=null && (date=crontrg.getFireTimeAfter(new Date()))!=null){
			return StringTools.date2String(date, "yyyy-MM-dd HH:mm:ss");
		}else{
			return "";
		}		
	}
	
	/**
	 * 
	* @Title: spiderTimeSlice 
	* @Description: TODO 从当前时间开始，对未来周期N天内的时间进行分片，获得M个无序时间点
	* @param @param configName  配置参数名
	* @param @return    设定文件 
	* @return Set<Date>    返回类型 
	* @throws
	 */
	public Set<Date> spiderTimeSliceSet(Date date,String configName)
	{
		date = date != null?date:new Date();
		ConfigManager configManager = ConfigManager.getInstance();
		//获取配置表时间段及任务并行个数
		String[] spiderTimeSlice = configManager.getParamNamesByConfigName("spider_time_slice");
		//获取周期天数N
		int spiderTimeCycle = Integer.valueOf(configManager.getParamValue(configName,"spider_time_cycle","5"));
		//获取时间片间隔
		int minTimeSlice = Integer.valueOf(configManager.getParamValue(configName,"min_time_slice","30"));
		
		Map<Integer,Integer> configMap = new HashMap<Integer,Integer>();
		if(spiderTimeSlice != null && spiderTimeSlice.length > 0)
		{
			Config config = null;
			for(int i=0;i<spiderTimeSlice.length;i++)
			{
				config = configManager.getConfigVo("spider_time_slice", spiderTimeSlice[i]);
				configMap.put(Integer.valueOf(config.getParamname()),Integer.valueOf(config.getParamvalue()));
			}
		}
		Set<Date> set = new HashSet<Date>();
		Calendar calendar = Calendar.getInstance();
		date = date != null ? date : new Date();
		calendar.setTime(date);
		calendar.add(Calendar.HOUR, 2);//2小时后开始
		calendar.add(Calendar.DAY_OF_YEAR, spiderTimeCycle);//+周期天数
		int nowhour = calendar.get(Calendar.HOUR_OF_DAY);
		int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);//获取+周期天数后的年度天数
		calendar.add(Calendar.DAY_OF_YEAR, -spiderTimeCycle);
		calendar.set(Calendar.MINUTE, 0);//分钟置0
		calendar.set(Calendar.SECOND, 0);//秒数置0
		while(true)
		{
			Integer hour = calendar.get(Calendar.HOUR_OF_DAY);
			//日期=当前+N天后的同一时刻表明一个周期结束，跳出循环
			if(dayOfYear == calendar.get(Calendar.DAY_OF_YEAR) 
					&& nowhour == hour)
				break;
			Integer num = configMap.get(hour);//获取小时数对应的最大任务数
			if(num != null && num > 0)
			{
				int sum = 0;
				int subSlice = minTimeSlice/num;
				//通过时间段任务并行数量，把时间间隔平均到每个并行任务上，保证时间片分布均匀
				for(int i =0;i<num;i++)
				{
					calendar.add(Calendar.MINUTE, subSlice);
					sum += subSlice;
					set.add(calendar.getTime());
				}
				calendar.add(Calendar.MINUTE, -sum);
				
			}
			calendar.add(Calendar.MINUTE, minTimeSlice);
			
		}
		Iterator<Date> iterator =  set.iterator();
		while(iterator.hasNext())
		{
			StringTools.generateCorn(iterator.next());
		}
		return set;
		
		
	}
	
	/**
	 * 
	* @Title: spiderTimeSlice 
	* @Description: TODO 从当前时间开始，对未来周期N天内的时间进行分片，获得M个有序时间点
	* @param @param configName  配置参数名
	* @param @return    设定文件 
	* @return Set<Date>    返回类型 
	* @throws
	 */
	public List<Date> spiderTimeSliceList(Date date,String configName)
	{
		date = date != null?date:new Date();
		ConfigManager configManager = ConfigManager.getInstance();
		//获取配置表时间段及任务并行个数
		String[] spiderTimeSlice = configManager.getParamNamesByConfigName("spider_time_slice");
		//获取周期天数N
		int spiderTimeCycle = Integer.valueOf(configManager.getParamValue(configName,"spider_time_cycle","5"));
		//获取时间片间隔
		int minTimeSlice = Integer.valueOf(configManager.getParamValue(configName,"min_time_slice","30"));
		
		Map<Integer,Integer> configMap = new HashMap<Integer,Integer>();
		if(spiderTimeSlice != null && spiderTimeSlice.length > 0)
		{
			Config config = null;
			for(int i=0;i<spiderTimeSlice.length;i++)
			{
				config = configManager.getConfigVo("spider_time_slice", spiderTimeSlice[i]);
				configMap.put(Integer.valueOf(config.getParamname()),Integer.valueOf(config.getParamvalue()));
			}
		}
		List<Date> list = new ArrayList<Date>();
		Calendar calendar = Calendar.getInstance();
		date = date != null ? date : new Date();
		calendar.setTime(date);
		calendar.add(Calendar.HOUR, 2);//2小时后开始
		calendar.add(Calendar.DAY_OF_YEAR, spiderTimeCycle);//+周期天数
		int nowhour = calendar.get(Calendar.HOUR_OF_DAY);
		int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);//获取+周期天数后的年度天数
		calendar.add(Calendar.DAY_OF_YEAR, -spiderTimeCycle);
		calendar.set(Calendar.MINUTE, 0);//分钟置0
		calendar.set(Calendar.SECOND, 0);//秒数置0
		while(true)
		{
			Integer hour = calendar.get(Calendar.HOUR_OF_DAY);
			//日期=当前+N天后的同一时刻表明一个周期结束，跳出循环
			if(dayOfYear == calendar.get(Calendar.DAY_OF_YEAR) 
					&& nowhour == hour)
				break;
			Integer num = configMap.get(hour);//获取小时数对应的最大任务数
			if(num != null && num > 0)
			{
				int sum = 0;
				int subSlice = minTimeSlice/num;
				//通过时间段任务并行数量，把时间间隔平均到每个并行任务上，保证时间片分布均匀
				for(int i =0;i<num;i++)
				{
					calendar.add(Calendar.MINUTE, subSlice);
					sum += subSlice;
					list.add(calendar.getTime());
				}
				calendar.add(Calendar.MINUTE, -sum);
				
			}
			calendar.add(Calendar.MINUTE, minTimeSlice);
			
		}
		Iterator<Date> iterator =  list.iterator();
		while(iterator.hasNext())
		{
			StringTools.generateCorn(iterator.next());
		}
		return list;
		
		
	}
	
	
}


